// Ninf-G-XX, ver. 0.1
// Copyright 2011 National Institute of Advanced Industrial Science and Technology
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <sstream>
#include <iostream>
#include <boost/format.hpp>

#include "StubObj.hpp"
#include "Types.hpp"
#include "FpInputStream.hpp"
#include "FpOutputStream.hpp"
#include "DataInputStream.hpp"
#include "DataOutputStream.hpp"
#include "Exception.hpp"
#include "GrpcException.hpp"

using namespace ninf::stub;
using namespace ninf::lib;
using namespace std;
using namespace boost;

StubObj :: StubObj(
  int     argc,
  char ** argv,
  FunctionInterfaceImpl * interface)
  :interface(interface)
{
  try {
    if (!parseArg(argc, argv))
      EXCEPTION("failed to get options");

    args = new Arg[interface->nParams];
    
    // read grpcDatas from files
    for (int i = 0; i < interface->getNParams(); i++) {
      args[i].gdata = new ninf::data::GrpcData((format("%1%.%2%") % metaFilePrefix % i).str());
      std::cout <<   *(args[i].gdata) << std::endl;
      std::cout  << "here-after" << std::endl;    
    }

      std::cout  << "before scalar" << std::endl;    
    // read Scalar
    for (int i = 0; i < interface->getNParams(); i++){
      std::cout  << "scalar " << i << std::endl;    
      if ((interface->params[i]->modeType == MODE_IN ||
	   interface->params[i]->modeType == MODE_INOUT ||
	   interface->params[i]->dataType == DT_FILENAME) &&
	  interface->params[i]->nDim == 0) {
	args[i].readFromGdata();
	//            string filename = (format("%1%.%2") % inputFilePrefix % i).str();
	//						FpInputStream   fis(filename);
	//						DataInputStream dis(&fis);
	//						args[i].readData(dis);
      }
    }

      std::cout  << "before setup shapes" << std::endl;        
    // setup arg shapes
    interface->setupStubArgs(args);
    
    for (int i = 0; i < interface->getNParams(); i++){
      if (interface->params[i]->nDim > 0)
	args[i].allocate(interface->shrink);
      args[i].gdata->immediate = args[i].v.p;
    }

      std::cout  << "here-out" << std::endl;    
    // read Args
    for (int i = 0; i < interface->getNParams(); i++){
      std::cout  << "here--" << std::endl;
      if ((interface->params[i]->modeType == MODE_IN ||
	   interface->params[i]->modeType == MODE_INOUT) &&
	  interface->params[i]->nDim > 0){
	args[i].readFromGdata();
	//          string filename = (format("%1%.%2") % inputFilePrefix % i).str();
	//            FpInputStream   fis(filename);
	//						DataInputStream dis(&fis);
	//						args[i].readData(dis);
      }
    }
  } catch (GrpcException e) {
    std::cerr << e << std::endl;
  } catch (Exception e) {
    std::cerr << e << std::endl;
  }
}

bool
StubObj :: parseArg(int argc, char ** argv)
{
  int i = 0;
  char ** index = argv;
  for (; *argv != NULL; argv++){

    if (strcasecmp(*argv, "-inputfile") == 0){
      inputFilePrefix  = *(++argv);
    } else
    if (strcasecmp(*argv, "-outputfile") == 0){
        outputFilePrefix  = *(++argv);
    } else
     if (strcasecmp(*argv, "-metafile") == 0){
          metaFilePrefix  = *(++argv);
    } else {
      i++;
      *(index++) = *(argv);
    }
  }
  *(index++) = *(argv);

  if (inputFilePrefix.empty() || outputFilePrefix.empty())
    return false;
  return true;
}

void
StubObj :: setArg(void * pointer, int argNum){
  Arg * arg = args + argNum;
  if (arg->nDim == 0){
    switch (arg->dataType){
    case DT_CHAR:
      *((char *)pointer) = arg->v.c; break;
    case DT_SHORT:
      *((short *)pointer) = arg->v.s; break;
    case DT_INT:
      *((int *)pointer) = arg->v.i; break;
    case DT_LONG:
      *((long *)pointer) = arg->v.l; break;
    case DT_FLOAT:
      *((float *)pointer) = arg->v.f; break;
    case DT_DOUBLE:
      *((double *)pointer) = arg->v.d; break;
    case DT_STRING_TYPE:
      *((char **)pointer) = (char *)arg->v.p; break;
    case DT_FILENAME:
      *((char **)pointer) = (char *)arg->v.p; break;
    default:
      EXCEPTION("the data type is not supported for scalar");
    }
  } else {
    *((void **)pointer) = arg->v.p;
  }
}

void
StubObj :: begin(){
  // nothing to do
}

void
StubObj :: end(){
try {
  // writeOutArgs
		for (int i = 0; i < interface->getNParams(); i++)
				if ((interface->params[i]->modeType == MODE_OUT ||
						 interface->params[i]->modeType == MODE_INOUT) &&
						interface->params[i]->nDim > 0) {
          args[i].writeToGdata();

//				  string filename = (format("%1%.%2") % outputFilePrefix % i).str();
//	          FpOutputStream   fos(filename);
//						DataOutputStream dos(&fos);
//						args[i].writeData(dos);
				}

} catch (GrpcException e) {
  std::cerr << e << std::endl;
} catch (Exception e) {
  std::cerr << e << std::endl;
}

}

